package com.universest.swordholder.model

import android.os.Build
import android.os.Environment
import com.universest.swordholder.SwordHolderApplication
import com.universest.swordholder.data.dao.Passage
import com.universest.swordholder.data.dao.Volume
import com.universest.swordholder.data.getUserDb
import com.universest.swordholder.data.repository.BookRepository
import com.universest.swordholder.data.repository.LongTextRepository
import com.universest.swordholder.data.repository.PassageRepository
import com.universest.swordholder.data.repository.VolumeRepository
import com.universest.swordholder.task.AbstractTask
import com.universest.swordholder.task.NeedPrepareTask
import com.universest.swordholder.task.Task
import com.universest.swordholder.task.combineTasks
import com.universest.swordholder.tools.toFormattedDate
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import java.io.BufferedWriter
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream

/**
 * 小说导出器类，负责将指定书籍导出为文本文件
 * @param bookId 需要导出的小说ID
 */
class NovelExporter(val bookId: Int) {

    // 应用上下文
    val context = SwordHolderApplication.instance

    // 各种数据仓库实例
    val bookRepository = BookRepository(getUserDb())
    val volumeRepository = VolumeRepository(getUserDb())
    val passageRepository = PassageRepository(getUserDb())
    val longTextRepository = LongTextRepository(getUserDb())

    /**
     * 创建导出任务
     * @return 返回一个可执行的抽象任务对象
     */
    fun createTask(): AbstractTask<Unit, String> {
        return NeedPrepareTask(
            name = "导出小说",
            prepareTask = Task(
                name = "准备数据",
                progressMaxValue = 100,
                initialMessage = "正在准备数据...",
                taskFunc = {
                    // 获取书籍信息
                    val book = bookRepository.getBookById(bookId).first()
                    if (book == null) throw Exception("未找到该小说")
                    updateMessage("正在导出《${book.bookName}》...")

                    // 获取卷信息
                    val volumes = volumeRepository.getVolumeByBookId(bookId).first()
                    val fileName = "${book.bookName}${System.currentTimeMillis().toFormattedDate("yyyy-MM-dd_HH-mm-ss")}.txt"
                    // 创建输出文件流
                    val writer = createOutputStream(fileName)?.bufferedWriter()
                    if (writer == null) {
                        throw Exception("创建输出文件失败")
                    }

                    // 获取无卷章节
                    val nonVolumePassages = passageRepository.getPassagesByBookIdAndVolumeId(bookId, -1).first()
                    checkCancelled()
                    // 导出无卷章节的任务
                    val task = Task<Unit, Unit>(
                        name = "导出无卷章节",
                        progressMaxValue = nonVolumePassages.size,
                        initialMessage = "正在导出无卷章节...",
                    ) {
                        exportNonVolumePassages(nonVolumePassages, writer)
                    }
                        // 组合导出各卷章节的任务
                        .combineTask(
                            "",
                            exportEachVolumeTasks(volumes, writer)
                        )
                        .combineTask<String> {
                            return@combineTask fileName
                        }
                        .finallyDo {
                            // 关闭文件流
                            writer.close()
                        }
                    task
                }
            )
        ).withContext(Dispatchers.IO)
    }

    private fun exportEachVolumeTasks(
        volumes: List<Volume>,
        writer: BufferedWriter
    ): AbstractTask<Unit, Unit> = combineTasks(
        "导出小说",
        volumes.map { volume ->
            NeedPrepareTask<Unit, Unit>(
                name = "导出卷${volume.name}",
                prepareTask = Task(name = "准备数据") {
                    checkCancelled()
                    val passages =
                        passageRepository.getPassagesByBookIdAndVolumeId(bookId, volume.volumeId)
                            .first()
                    exportVolumeTask(volume, passages, writer)
                }
            )
        }
    )

    private suspend fun Task.TaskScope<Unit, Unit>.exportNonVolumePassages(
        nonVolumePassages: List<Passage>,
        writer: BufferedWriter
    ) {
        nonVolumePassages.forEach {
            checkCancelled()
            updateMessage("导出 ${it.title}")
            writer.write(it.title)
            writer.write("\n\n")
            longTextRepository.getTextById(it.contentId).first()?.let {
                writer.write(it.content)
                writer.write("\n\n")
            }
        }
    }

    private fun exportVolumeTask(
        volume: Volume,
        passages: List<Passage>,
        writer: BufferedWriter
    ): Task<Unit, Unit> =
        Task<Unit, Unit>(name = "导出卷${volume.name}", progressMaxValue = passages.size) {
            checkCancelled()
            writer.write(volume.name)
            writer.write("\n\n")
            passages.forEachIndexed { index, it ->
                checkCancelled()
                updateMessage("导出 ${it.title}")
                writer.write(it.title)
                writer.write("\n\n")
                longTextRepository.getTextById(it.contentId).first()?.let {
                    writer.write(it.content)
                    writer.write("\n\n")
                }
                updateProgress(index + 1,passages.size)
            }
        }

    /**
     * 根据Android版本创建输出流
     * @param fileName 文件名
     * @return 输出流对象，创建失败返回null
     */
    fun createOutputStream(fileName: String): OutputStream? {
        val context = SwordHolderApplication.instance
        return try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                // Android 10+ 使用 MediaStore API
                val contentValues = android.content.ContentValues().apply {
                    put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, fileName)
                    put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "application/octet-stream")
                    put(
                        android.provider.MediaStore.MediaColumns.RELATIVE_PATH,
                        Environment.DIRECTORY_DOWNLOADS
                    )
                }

                val resolver = context.contentResolver
                val uri = resolver.insert(
                    android.provider.MediaStore.Downloads.EXTERNAL_CONTENT_URI,
                    contentValues
                )

                uri?.let { resolver.openOutputStream(it) }
            } else {
                // Android 9 及以下使用传统文件 API
                val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                if (!downloadsDir.exists()) {
                    downloadsDir.mkdirs()
                }

                val file = File(downloadsDir, fileName)
                FileOutputStream(file)
            }
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }
}
